#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include <functional>
#include "rocksdb/status.h"

namespace rocksdb {
  class ColumnFamilyHandle;
  class DB;
    class Comparator;
    struct Options;
}


namespace helper {
namespace rocksdb {

class Options;
class Table;

class Rocksdb {
public:
    using Slice = ::rocksdb::Slice;
    using Status = ::rocksdb::Status;

    explicit Rocksdb(const std::string & name, ::rocksdb::Comparator * comparator = nullptr);
    ~Rocksdb() ;

    static bool exist(const std::string & dbname);
    bool touch(const std::string & dbname, ::rocksdb::Options & options);

    bool isOpened() const;
    bool createIfMissing() ;
    bool openExist() ;

    void close();

  Status put(const Slice & key, const Slice & value);
  Status get(const Slice & key, std::string & value);
  Status del(const Slice & key);

  bool size(size_t & sz) const;
  //void clear() ; TODO:
    
  using Visitor = std::function<bool(const Slice & key, const Slice & value)>;
  bool foreach(const Visitor & v, const Slice & start = Slice(), const Slice & end = Slice()) const; 


  using Tables = std::unordered_map<std::string, ::rocksdb::ColumnFamilyHandle*>;
  inline const Tables & tables() const {
      return _tables;
  }

  std::pair<bool, ::rocksdb::ColumnFamilyHandle*> isTableExist(const std::string & name) const;
  std::shared_ptr<Table> getTable(const std::string & name) const;
  std::shared_ptr<Table> createTable(const std::string & name);
  bool dropTable(const std::string & name);
  bool closeTable(const std::string & name);

  static bool destroy(const std::string & name);

protected:
  bool _closeColumnFamilyHandle(::rocksdb::ColumnFamilyHandle * handle);
  bool _openExist();

private:
    std::shared_ptr<::rocksdb::DB> _db;
    std::string _name;
    bool _isOpened = false;


    Options * _options;

  Tables _tables;
  friend class Table;
};

}//end namespace rocksdb
}//end namespace helper
